import re
from typing import Annotated, Dict, List, Literal, Optional, Union

from pydantic import BaseModel, Field, TypeAdapter


class RustcErrorText(BaseModel):
    text: str
    highlight_start: int
    highlight_end: int


class RustcErrorSpan(BaseModel):
    file_name: str
    byte_start: int
    byte_end: int
    line_start: int
    line_end: int
    column_start: int
    column_end: int
    is_primary: bool
    text: List["RustcErrorText"]
    label: Optional[str]
    suggested_replacement: Optional[str]
    suggestion_applicability: Optional[str]
    expansion: Optional["RustcErrorExpansion"]


class RustcErrorCode(BaseModel):
    code: str
    explanation: Optional[str]


class RustcErrorExpansion(BaseModel):
    span: RustcErrorSpan
    macro_decl_name: str
    def_site_span: Optional[RustcErrorSpan]


class RustcErrorMessages(BaseModel):
    message_type: Optional[str] = Field(alias="$message_type", default=None)  # type: ignore
    message: str
    level: Literal["error", "warning", "note", "help", "failure-note", "error: internal compiler error"]
    code: Optional[RustcErrorCode]
    spans: List[RustcErrorSpan]
    children: List["RustcErrorMessages"]
    rendered: Optional[str]


class CargoOutputTarget(BaseModel):
    kind: List[str]
    crate_types: List[str]
    name: str
    src_path: str
    edition: str
    doc: bool
    doctest: bool
    test: bool


class CargoOutputProfile(BaseModel):
    opt_level: str
    debuginfo: int
    debug_assertions: bool
    overflow_checks: bool
    test: bool


class CargoMessageCompilerMessage(BaseModel):
    reason: Literal["compiler-message"]
    package_id: str

    manifest_path: str
    target: CargoOutputTarget

    message: RustcErrorMessages


class CargoMessageCompilerArtifact(BaseModel):
    reason: Literal["compiler-artifact"]
    package_id: str

    manifest_path: str
    target: CargoOutputTarget

    profile: CargoOutputProfile
    features: List[str]
    filenames: List[str]
    executable: Optional[str]
    fresh: bool


class CargoMessageBuildScriptExecuted(BaseModel):
    reason: Literal["build-script-executed"]
    package_id: str

    linked_libs: List[str]
    linked_paths: List[str]
    cfgs: List[str]
    env: List[str]
    out_dir: str


class CargoMessageBuildFinished(BaseModel):
    reason: Literal["build-finished"]
    success: bool


CargoMessage = Annotated[
    Union[CargoMessageCompilerMessage, CargoMessageCompilerArtifact, CargoMessageBuildScriptExecuted, CargoMessageBuildFinished],
    Field(discriminator="reason"),
]

CargoMessageTypeAdapter: TypeAdapter[CargoMessage] = TypeAdapter(CargoMessage)
